package com.qingzhou.web.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.mail.MailUtil;
import com.alibaba.fastjson2.JSONObject;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.solon.service.impl.ServiceImpl;
import com.qingzhou.web.repository.dao.PatientDao;
import com.qingzhou.web.repository.dao.VisitDao;
import com.qingzhou.web.repository.entity.PatientEntity;
import com.qingzhou.web.repository.entity.SurgeryEntity;
import com.qingzhou.web.repository.entity.VisitEntity;
import com.qingzhou.web.repository.mapper.VisitMapper;
import com.qingzhou.web.service.*;
import com.qingzhou.web.service.impl.convert.DistrictConverter;
import com.qingzhou.web.service.impl.params.request.*;
import com.qingzhou.web.service.impl.params.vo.VisitVo;
import com.qingzhou.web.service.util.DictUtil;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import org.noear.solon.data.annotation.Tran;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Component
@Slf4j
public class VisitServiceImpl extends ServiceImpl<VisitMapper, VisitEntity> implements VisitService {
    @Inject
    VisitDao visitDao;
    @Inject
    ConvertHelper convertHelper;
    @Inject
    DataCheckLogService dataCheckLogService;
    @Inject
    PatientDao patientDao;

    @Override
    @Tran
    public int add(VisitAddForm form) {
        Assert.isTrue(StrUtil.isNotEmpty(form.getPatientCode()), "患者编号不允许为空");

        // 患者的生存状态跟着变
        this.updateLifeStatus(form.getLifeStatus(), form.getPatientCode());

        // 随访日期影响下次随访提醒日期
        this.updateVisitRemindDate(form.getPatientCode(), DateUtil.offsetMonth(form.getFollowTime(),3));

        VisitEntity entity = BeanUtil.copyProperties(form, VisitEntity.class);
        entity.setStatus("create");
        return visitDao.add(entity);
    }

    @Override
    public int delete(VisitDeleteForm form) {
        VisitEntity entity = visitDao.getById(form.getId());
        Assert.isTrue(ObjUtil.isNotNull(entity), "数据不见了");
        Assert.isTrue(StrUtil.equalsIgnoreCase("create", entity.getStatus()), "该状态不允许删除");

        return visitDao.delete(form.getId());
    }

    @Override
    public Page<VisitVo> page(Page<VisitEntity> page, SubTablePageForm form) {
        Page<VisitEntity> paginate = visitDao.getMapper().paginate(page, QueryWrapper.create()
                .in("patient_code", form.getPatientCodeList())
                .orderBy("create_time desc"));
        return convertHelper.convertVisit(paginate);
    }

    @Override
    public VisitVo detail(VisitDetailForm form) {
        VisitEntity entity = visitDao.getById(form.getId());
        Assert.isTrue(ObjUtil.isNotNull(entity), "数据不见了");
        return convertHelper.convert(entity);
    }

    @Override
    @Tran
    public int edit(VisitEditForm form) {
        VisitEntity entity = visitDao.getById(form.getId());
        Assert.isTrue(ObjUtil.isNotNull(entity), "数据不见了");
        Assert.isTrue(StrUtil.equalsIgnoreCase("create", entity.getStatus()), "该状态不允许编辑");
        boolean isChangedFollowTime = DateUtil.compare(form.getFollowTime(),entity.getFollowTime())!=0;

        BeanUtil.copyProperties(form, entity,"patientCode"); //患者编号不能变
        int rows = visitDao.update(entity);

        // 患者的生存状态跟着变
        this.updateLifeStatus(form.getLifeStatus(), entity.getPatientCode());

        // 随访日期影响下次随访提醒日期
        if(isChangedFollowTime && this.isLatestData(entity.getId())){
            this.updateVisitRemindDate(entity.getPatientCode(), DateUtil.offsetMonth(form.getFollowTime(),1));
        }

        return rows;
    }

    @Override
    @Tran
    public int forceEdit(VisitForceEditForm form) {
        VisitEntity entity = visitDao.getById(form.getId());
        Assert.isTrue(ObjUtil.isNotNull(entity), "数据不见了");
        Assert.isTrue(StrUtil.equalsIgnoreCase("done", entity.getStatus()), "该状态不允许数据检查");
        boolean isChangedFollowTime = DateUtil.compare(form.getFollowTime(),entity.getFollowTime())!=0;

        JSONObject diffContent = DataCheckLogServiceImpl.diff(entity, form, new String[]{});
        BeanUtil.copyProperties(form, entity,"patientCode"); //患者编号不能变
        int rows = visitDao.update(entity);

        // 患者的生存状态跟着变
        this.updateLifeStatus(form.getLifeStatus(), entity.getPatientCode());

        // 随访日期影响下次随访提醒日期
        if(isChangedFollowTime && this.isLatestData(entity.getId())){
            this.updateVisitRemindDate(entity.getPatientCode(), DateUtil.offsetMonth(form.getFollowTime(),3));
        }

        if (rows > 0 && MapUtil.isNotEmpty(diffContent)) {
            DataCheckLogAddForm addForm = new DataCheckLogAddForm(EdcConstants.EDC_VISIT, diffContent, entity.getPatientCode());
            dataCheckLogService.add(addForm);
        }
        return rows;
    }

    @Override
    @Tran
    public int done(VisitDoneForm form) {
        VisitEntity entity = visitDao.getById(form.getId());
        Assert.isTrue(ObjUtil.isNotNull(entity), "数据不见了");
        Assert.isTrue(StrUtil.equalsIgnoreCase("create", entity.getStatus()), "该状态不允许核实");
        boolean isChangedFollowTime = DateUtil.compare(form.getFollowTime(),entity.getFollowTime())!=0;

        BeanUtil.copyProperties(form, entity,"patientCode"); //患者编号不能变
        entity.setStatus("done");
        int update = visitDao.update(entity);

        // 患者的生存状态跟着变
        this.updateLifeStatus(form.getLifeStatus(), entity.getPatientCode());

        // 随访日期影响下次随访提醒日期
        if(isChangedFollowTime && this.isLatestData(entity.getId())){
            this.updateVisitRemindDate(entity.getPatientCode(), DateUtil.offsetMonth(form.getFollowTime(),3));
        }

        return update;
    }

    @Override
    public int stop(VisitStopForm form) {
        VisitEntity entity = visitDao.getById(form.getId());
        Assert.isTrue(ObjUtil.isNotNull(entity), "数据不见了");
        Assert.isTrue(!StrUtil.equalsIgnoreCase("stop", entity.getStatus()), "该状态不允许终止");

        entity.setStatus("stop");
        entity.setStopReason(form.getStopReason());
        return visitDao.update(entity);
    }

    @Override
    @Tran
    public int visitRemind() {
        List<PatientEntity> patientEntities = patientDao.getMapper().selectListByQuery(QueryWrapper.create().isNotNull("visit_remind_date"));

        // 过滤随访提醒日期为当天或小于当天的
        Date today = new Date();
        List<PatientEntity> toBeMail = patientEntities.stream().filter(patient -> {
            Date visitRemindDate = patient.getVisitRemindDate();
            return DateUtil.compare(visitRemindDate, today) <= 0;
        }).collect(Collectors.toList());

        // 邮件通知
        if (CollUtil.isNotEmpty(toBeMail)) {
            toBeMail.forEach(item -> {
                String districtCode = item.getDistrictCode();
                String convertString = DistrictConverter.getConvertString(districtCode);
                String group = DictUtil.getLabel(item.getBelongingGroup(),"belonging_group_dict");
                String sendTo = "jiangconghui@biokanghui.com";
                String cc = "jiangconghui@biokanghui.com";
                String html = "您好 <div>受检者：{}-{}，已到随访时间，请安排随访。</div>";
                //TODO 只有两个院区有邮件，其他暂时都发送给聪辉的。
                if(StrUtil.equals(convertString,"西直门院区")){
                    sendTo="liuxinying@oleading.com.cn";
                }else if(StrUtil.equals(convertString,"通州院区")){
                    sendTo="liyufang@oleading.com.cn";
                }else if(StrUtil.equals(group,"观察组")){
                    html = "您好 <div>受检者：{}-{}，已到随访时间，请随访是否复发。</div>";
                }else if(StrUtil.equals(group,"干预组")){
                    html = "您好 <div>受检者：{}-{}，已到随访时间，请安排采样。</div>";
                }
                String content = StrUtil.format(html, item.getPatientCode(), item.getPatientName());
                try {
                    MailUtil.send(sendTo,cc,null, "随访提醒", content, true,null);
                    this.updateVisitRemindDate(item.getPatientCode(), DateUtil.offsetMonth(new Date(),3));
                }catch (Exception e){
                    log.error(StrUtil.format("随访提醒邮件通知失败：{}-{}",item.getPatientCode(), item.getPatientName()),e);
                }
            });
        }

        return toBeMail.size();
    }

    private boolean isLatestData(Long id) {
        List<VisitEntity> createTimeDesc = this.getMapper()
                .selectListByQuery(QueryWrapper.create().orderBy("create_time desc")
                        .select("id")
                        .limit(1));
        VisitEntity entity = createTimeDesc.get(0);
        return Objects.equals(entity.getId(), id);
    }

    private void updateLifeStatus(String lifeStatus, String patientCode) {
        PatientEntity patient = patientDao.selectOneByPatientCode(patientCode);
        patient.setLifeStatus(lifeStatus);
        patientDao.update(patient);
    }

    private void updateVisitRemindDate(String patientCode, Date nextRemindDate) {
        // 如果填了手术日期，就更新下次随访提醒日期
        if (ObjUtil.isNotNull(nextRemindDate)) {
            PatientEntity patient = patientDao.selectOneByPatientCode(patientCode);
            Assert.isTrue(ObjUtil.isNotNull(patient), "患者编号无效");
            patient.setVisitRemindDate(nextRemindDate);
            patientDao.update(patient);
        }
    }
}
